# load package(s) first
library(dplyr)

R has a sample dataframe “mtcars”.

mtcars

Using ggplot2 package

ggplot2 is a system for declaratively creating graphics, based on The Grammar of Graphics. You provide the data, tell ggplot2 how to map variables to aesthetics, what graphical primitives to use, and it takes care of the details. (https://ggplot2.tidyverse.org)

RStudio ggplot2 Cheat Sheet

# install.packages("ggplot2") # install only once
library(ggplot2) # load every session

Basic Syntax

ggplot(data = dataset, mapping = aes(x = xcol, y = ycol)) + geom_histogram()
  • ggplot layer: create a ggplot object. especially aes() specifies what columns of the data table will be used as visual attributes of graphical elements in the plot.
  • geom layer: define a shape of geometric plot
  • and more other layers

Aesthetics

colour Coloring outline
fill Coloring inside
linetype Line type
shape Shape of point
alpha Transparency

geom objects

geom_point() Scatter plot
geom_bar() Bar chart
geom_line() Line plot
geom_histogram() Histogram
geom_boxplot() Box plot

Inside aes(): variables from dataframe.
Outside aes(): options not from dataframe. —

Scatter plot geom_point()

ggplot(mtcars, aes(x = mpg, y = hp)) + geom_point()

Bar chart geom_bar()

ggplot(mtcars, aes(x = cyl)) + geom_bar()

Line plot geom_line()

ggplot(mtcars, aes(x = mpg, y = wt)) + geom_line()

Histogram geom_histogram()

ggplot(mtcars, aes(x = wt)) + geom_histogram()

Box plot geom_boxplot()

Use factor() to treat cyl as a discrete (categorical) variable.

ggplot(mtcars, aes(x = factor(cyl), y = wt)) + geom_boxplot()

ggplot(mtcars, aes(x = mpg, y = hp, colour = cyl)) + 
  geom_point(aes(color = factor(gear))) +
  geom_smooth(method = "lm") + 
  labs(title = "Miles per Gallon -vs- Horsepower")


storms dataframe

head(storms)

Bar plot

How many records are there in each year?

ggplot(storms, aes(x = year)) + geom_bar()

# this works as well
ggplot(storms) + geom_bar(aes(x = year))

Then, how many storms are there in each year?

Need some operation.

distinct(group_by(select(storms, year, name), year))
storms_year_name <- distinct(group_by(select(storms, year, name), year))

ggplot(storms_year_name) + geom_bar(aes(x = year))

# check
count(storms_year_name)

Histogram

storms75 <- filter(storms, year == 1975)

ggplot(storms75) + geom_histogram(aes(x = wind))

Change the bin width and compare.

ggplot(storms75, aes(x = wind)) + geom_histogram(binwidth = 5)

ggplot(storms75, aes(x = wind)) + geom_histogram(binwidth = 10)

Box plot

There are three storms in 1975: Amy, Caroline, and Doris.

unique(pull(storms75, name))
[1] "Amy"      "Caroline" "Doris"   

Compare the wind speeds of the three.

ggplot(storms75, aes(x = name, y = wind)) + geom_boxplot()

Density curve

ggplot(storms75, aes(x = wind)) + geom_density()

How is the distribution like?

ggplot(storms75, aes(x = wind, color = name)) + geom_density(aes(fill = name), alpha = 0.5)

To produce separated frames, use facet_wrap(). Facetting by name.

ggplot(storms75, aes(x = wind, color = name)) + 
  geom_density(aes(fill = name), alpha = 0.5) + 
  facet_wrap(~ name)

Scatter plot

amy75 <- filter(storms75, name == "Amy")
head(amy75)
ggplot(data = amy75, aes(x = 1:nrow(amy75), y = wind)) +
  geom_point() + 
  xlab("time (6 hours each)")

Line plot

For chronological graph, line plot is commonly used.

ggplot(data = amy75, aes(x = 1:nrow(amy75), y = wind)) +
  geom_point() + 
  geom_line() + 
  xlab("time")

Color by status.

ggplot(amy75, aes(x = 1:nrow(amy75), y = wind)) + 
  geom_line() + 
  geom_point(aes(color = status))

What about pressure?

ggplot(amy75, aes(x = 1:nrow(amy75), y = pressure)) + 
  geom_point(aes(color = status)) + 
  geom_line(linetype = "dashed")

Graphing pressure and taking into account the wind speed reflected in the size of points and line segments.

ggplot(amy75, aes(x = 1:nrow(amy75), y = pressure)) + 
  geom_line(aes(size = wind), color = "gray") + 
  geom_point(aes(color = status, size = wind)) 


Exercise

  1. Use “ggplot2” functions to make a single scatterplot of wind and pressure for all storms. Use category to add color to the dots.
ggplot(storms, aes(x = wind, y = pressure)) + 
  geom_point(aes(color = category))

  1. Use “ggplot2” functions to make a scatterplot of wind and pressure for all storms, facetting by month, and using category to differentiate by color.
ggplot(storms, aes(x = wind, y = pressure)) + 
  geom_point(aes(color = category)) + 
  facet_wrap(~ month)

  1. Use “ggplot2” functions to make a scatterplot of wind and pressure for all storms, but now create facets based on month. Feel free to add some amount of alpha transparency to the color of dots.
ggplot(storms, aes(x = wind, y = pressure)) + 
  geom_point(aes(color = category), alpha = 0.2) + 
  facet_wrap(~ month)

  1. Create boxplots of pressure, for storms in 1980. You can also try graphing violins (geom_violin()) instead of boxplots (geom_boxplot()).
storms80 <- filter(storms, year == 1980)

ggplot(storms80, aes(x = name, y = pressure)) + 
  geom_boxplot()


ggplot(storms80, aes(x = name, y = pressure)) + 
  geom_violin()

  1. Make a scatterplot of wind (x-axis) and ts_diameter (y-axis), and add a regression line—via geom_smooth().
ggplot(storms, aes(x = wind, y = ts_diameter)) + 
  geom_point(na.rm = TRUE) + 
  geom_smooth(method = "lm", na.rm = TRUE)

Try geom_smooth() with method = lm to fit a least squares regression line.

Try geom_smooth() with method = loess to fit a local polynomial regression.

ggplot(storms, aes(x = wind, y = ts_diameter)) + 
  geom_point(na.rm = TRUE) + 
  geom_smooth(method = "loess", na.rm = TRUE)

  1. Repeat the previous scatterplot of wind (x-axis) and ts_diameter (y-axis), but now use status to color code the points, and use the alpha argument to add some transparency to the dots.
ggplot(storms, aes(x = wind, y = ts_diameter)) + 
  geom_point(aes(color = status), alpha = 0.5, na.rm = TRUE) + 
  geom_smooth(method = "lm", na.rm = TRUE)

  1. Take a look at the cheatsheet of “ggplot2” and make at least 5 more different graphs (e.g. of one variable, of two variables, of three variables).
# one variable
ggplot(storms) + geom_qq(aes(sample = pressure))


ggplot(storms) + geom_bar(aes(x = status))


# two variables
ggplot(count(storms_year_name), aes(x = year, y = n)) + geom_line()


ggplot(storms, aes(x = wind, y = pressure)) + geom_density2d()


# three variables
ggplot(storms, aes(x = wind, y = pressure)) + geom_tile(aes(fill = status))

LS0tCnRpdGxlOiAiZ2dwbG90IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7cn0KIyBsb2FkIHBhY2thZ2UocykgZmlyc3QKbGlicmFyeShkcGx5cikKYGBgCgpSIGhhcyBhIHNhbXBsZSBkYXRhZnJhbWUgIm10Y2FycyIuCmBgYHtyfQptdGNhcnMKYGBgCgojIFVzaW5nIGBnZ3Bsb3QyYCBwYWNrYWdlCgo+IGdncGxvdDIgaXMgYSBzeXN0ZW0gZm9yIGRlY2xhcmF0aXZlbHkgY3JlYXRpbmcgZ3JhcGhpY3MsIGJhc2VkIG9uIFRoZSBHcmFtbWFyIG9mIEdyYXBoaWNzLiBZb3UgcHJvdmlkZSB0aGUgZGF0YSwgdGVsbCBnZ3Bsb3QyIGhvdyB0byBtYXAgdmFyaWFibGVzIHRvIGFlc3RoZXRpY3MsIHdoYXQgZ3JhcGhpY2FsIHByaW1pdGl2ZXMgdG8gdXNlLCBhbmQgaXQgdGFrZXMgY2FyZSBvZiB0aGUgZGV0YWlscy4gKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnKQoKW1JTdHVkaW8gZ2dwbG90MiBDaGVhdCBTaGVldF0oaHR0cHM6Ly9naXRodWIuY29tL3JzdHVkaW8vY2hlYXRzaGVldHMvcmF3L21hc3Rlci9kYXRhLXZpc3VhbGl6YXRpb24tMi4xLnBkZikKCmBgYHtyfQojIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKSAjIGluc3RhbGwgb25seSBvbmNlCmxpYnJhcnkoZ2dwbG90MikgIyBsb2FkIGV2ZXJ5IHNlc3Npb24KYGBgCgojIyMgQmFzaWMgU3ludGF4CgpgYGAKZ2dwbG90KGRhdGEgPSBkYXRhc2V0LCBtYXBwaW5nID0gYWVzKHggPSB4Y29sLCB5ID0geWNvbCkpICsgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKLSAqKmdncGxvdCBsYXllcioqOiBjcmVhdGUgYSBnZ3Bsb3Qgb2JqZWN0LiBlc3BlY2lhbGx5IGBhZXMoKWAgc3BlY2lmaWVzIHdoYXQgY29sdW1ucyBvZiB0aGUgZGF0YSB0YWJsZSB3aWxsIGJlIHVzZWQgYXMgdmlzdWFsIGF0dHJpYnV0ZXMgb2YgZ3JhcGhpY2FsIGVsZW1lbnRzIGluIHRoZSBwbG90LiAgCi0gKipnZW9tIGxheWVyKio6IGRlZmluZSBhIHNoYXBlIG9mIGdlb21ldHJpYyBwbG90ICAKLSBhbmQgbW9yZSBvdGhlciBsYXllcnMKCiMjIyBBZXN0aGV0aWNzCnx8fAp8LXwtfAp8YGNvbG91cmB8Q29sb3Jpbmcgb3V0bGluZXwKfGBmaWxsYHxDb2xvcmluZyBpbnNpZGV8CnxgbGluZXR5cGVgfExpbmUgdHlwZXwKfGBzaGFwZWB8U2hhcGUgb2YgcG9pbnR8CnxgYWxwaGFgfFRyYW5zcGFyZW5jeXwKCiMjIyBnZW9tIG9iamVjdHMKfHx8CnwtfC18CnxgZ2VvbV9wb2ludCgpYHxTY2F0dGVyIHBsb3R8CnxgZ2VvbV9iYXIoKWB8QmFyIGNoYXJ0fAp8YGdlb21fbGluZSgpYHxMaW5lIHBsb3R8CnxgZ2VvbV9oaXN0b2dyYW0oKWB8SGlzdG9ncmFtfAp8YGdlb21fYm94cGxvdCgpYHxCb3ggcGxvdHwKCkluc2lkZSBgYWVzKClgOiB2YXJpYWJsZXMgZnJvbSBkYXRhZnJhbWUuICAKT3V0c2lkZSBgYWVzKClgOiBvcHRpb25zIG5vdCBmcm9tIGRhdGFmcmFtZS4KLS0tCgojIyMjIFNjYXR0ZXIgcGxvdCBgZ2VvbV9wb2ludCgpYAoKYGBge3J9CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gbXBnLCB5ID0gaHApKSArIGdlb21fcG9pbnQoKQpgYGAKCiMjIyMgQmFyIGNoYXJ0IGBnZW9tX2JhcigpYAoKYGBge3J9CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gY3lsKSkgKyBnZW9tX2JhcigpCmBgYAoKIyMjIyBMaW5lIHBsb3QgYGdlb21fbGluZSgpYAoKYGBge3J9CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gbXBnLCB5ID0gd3QpKSArIGdlb21fbGluZSgpCmBgYAoKIyMjIyBIaXN0b2dyYW0gYGdlb21faGlzdG9ncmFtKClgCgpgYGB7cn0KZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCkpICsgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKCiMjIyMgQm94IHBsb3QgYGdlb21fYm94cGxvdCgpYAoKVXNlIGBmYWN0b3IoKWAgdG8gdHJlYXQgYGN5bGAgYXMgYSBkaXNjcmV0ZSAoY2F0ZWdvcmljYWwpIHZhcmlhYmxlLgoKYGBge3J9CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gZmFjdG9yKGN5bCksIHkgPSB3dCkpICsgZ2VvbV9ib3hwbG90KCkKYGBgCgoKCmBgYHtyfQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZywgeSA9IGhwLCBjb2xvdXIgPSBjeWwpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZmFjdG9yKGdlYXIpKSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsgCiAgbGFicyh0aXRsZSA9ICJNaWxlcyBwZXIgR2FsbG9uIC12cy0gSG9yc2Vwb3dlciIpCmBgYAoKCi0tLQoKIyMgYHN0b3Jtc2AgZGF0YWZyYW1lCgpgYGB7cn0KaGVhZChzdG9ybXMpCmBgYAoKIyMjIEJhciBwbG90CkhvdyBtYW55IHJlY29yZHMgYXJlIHRoZXJlIGluIGVhY2ggeWVhcj8KCmBgYHtyfQpnZ3Bsb3Qoc3Rvcm1zLCBhZXMoeCA9IHllYXIpKSArIGdlb21fYmFyKCkKYGBgCmBgYHtyfQojIHRoaXMgd29ya3MgYXMgd2VsbApnZ3Bsb3Qoc3Rvcm1zKSArIGdlb21fYmFyKGFlcyh4ID0geWVhcikpCmBgYAoKVGhlbiwgaG93IG1hbnkgc3Rvcm1zIGFyZSB0aGVyZSBpbiBlYWNoIHllYXI/CgpOZWVkIHNvbWUgb3BlcmF0aW9uLgoKYGBge3J9CmRpc3RpbmN0KGdyb3VwX2J5KHNlbGVjdChzdG9ybXMsIHllYXIsIG5hbWUpLCB5ZWFyKSkKYGBgCgpgYGB7cn0Kc3Rvcm1zX3llYXJfbmFtZSA8LSBkaXN0aW5jdChncm91cF9ieShzZWxlY3Qoc3Rvcm1zLCB5ZWFyLCBuYW1lKSwgeWVhcikpCgpnZ3Bsb3Qoc3Rvcm1zX3llYXJfbmFtZSkgKyBnZW9tX2JhcihhZXMoeCA9IHllYXIpKQpgYGAKCmBgYHtyfQojIGNoZWNrCmNvdW50KHN0b3Jtc195ZWFyX25hbWUpCmBgYAoKIyMjIEhpc3RvZ3JhbQoKYGBge3J9CnN0b3Jtczc1IDwtIGZpbHRlcihzdG9ybXMsIHllYXIgPT0gMTk3NSkKCmdncGxvdChzdG9ybXM3NSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IHdpbmQpKQpgYGAKCkNoYW5nZSB0aGUgYmluIHdpZHRoIGFuZCBjb21wYXJlLgoKYGBge3J9CmdncGxvdChzdG9ybXM3NSwgYWVzKHggPSB3aW5kKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUpCmdncGxvdChzdG9ybXM3NSwgYWVzKHggPSB3aW5kKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEwKQpgYGAKCiMjIyBCb3ggcGxvdAoKVGhlcmUgYXJlIHRocmVlIHN0b3JtcyBpbiAxOTc1OiBBbXksIENhcm9saW5lLCBhbmQgRG9yaXMuCgpgYGB7cn0KdW5pcXVlKHB1bGwoc3Rvcm1zNzUsIG5hbWUpKQpgYGAKCkNvbXBhcmUgdGhlIHdpbmQgc3BlZWRzIG9mIHRoZSB0aHJlZS4KCmBgYHtyfQpnZ3Bsb3Qoc3Rvcm1zNzUsIGFlcyh4ID0gbmFtZSwgeSA9IHdpbmQpKSArIGdlb21fYm94cGxvdCgpCmBgYAoKIyMjIERlbnNpdHkgY3VydmUKCmBgYHtyfQpnZ3Bsb3Qoc3Rvcm1zNzUsIGFlcyh4ID0gd2luZCkpICsgZ2VvbV9kZW5zaXR5KCkKYGBgCgpIb3cgaXMgdGhlIGRpc3RyaWJ1dGlvbiBsaWtlPwoKYGBge3J9CmdncGxvdChzdG9ybXM3NSwgYWVzKHggPSB3aW5kLCBjb2xvciA9IG5hbWUpKSArIAogIGdlb21fZGVuc2l0eShhZXMoZmlsbCA9IG5hbWUpLCBhbHBoYSA9IDAuNSkKYGBgCgpUbyBwcm9kdWNlIHNlcGFyYXRlZCBmcmFtZXMsIHVzZSBgZmFjZXRfd3JhcCgpYC4gRmFjZXR0aW5nIGJ5IGBuYW1lYC4KCmBgYHtyfQpnZ3Bsb3Qoc3Rvcm1zNzUsIGFlcyh4ID0gd2luZCwgY29sb3IgPSBuYW1lKSkgKyAKICBnZW9tX2RlbnNpdHkoYWVzKGZpbGwgPSBuYW1lKSwgYWxwaGEgPSAwLjUpICsgCiAgZmFjZXRfd3JhcCh+IG5hbWUpCmBgYAoKIyMjIFNjYXR0ZXIgcGxvdAoKYGBge3J9CmFteTc1IDwtIGZpbHRlcihzdG9ybXM3NSwgbmFtZSA9PSAiQW15IikKaGVhZChhbXk3NSkKYGBgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBhbXk3NSwgYWVzKHggPSAxOm5yb3coYW15NzUpLCB5ID0gd2luZCkpICsKICBnZW9tX3BvaW50KCkgKyAKICB4bGFiKCJ0aW1lICg2IGhvdXJzIGVhY2gpIikKYGBgCgojIyMgTGluZSBwbG90CgpGb3IgY2hyb25vbG9naWNhbCBncmFwaCwgbGluZSBwbG90IGlzIGNvbW1vbmx5IHVzZWQuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBhbXk3NSwgYWVzKHggPSAxOm5yb3coYW15NzUpLCB5ID0gd2luZCkpICsKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX2xpbmUoKSArIAogIHhsYWIoInRpbWUiKQpgYGAKCkNvbG9yIGJ5IGBzdGF0dXNgLgoKYGBge3J9CmdncGxvdChhbXk3NSwgYWVzKHggPSAxOm5yb3coYW15NzUpLCB5ID0gd2luZCkpICsgCiAgZ2VvbV9saW5lKCkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHN0YXR1cykpCmBgYAoKV2hhdCBhYm91dCBwcmVzc3VyZT8KCmBgYHtyfQpnZ3Bsb3QoYW15NzUsIGFlcyh4ID0gMTpucm93KGFteTc1KSwgeSA9IHByZXNzdXJlKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHN0YXR1cykpICsgCiAgZ2VvbV9saW5lKGxpbmV0eXBlID0gImRhc2hlZCIpCmBgYAoKR3JhcGhpbmcgcHJlc3N1cmUgYW5kIHRha2luZyBpbnRvIGFjY291bnQgdGhlIHdpbmQgc3BlZWQgcmVmbGVjdGVkIGluIHRoZSBzaXplIG9mIHBvaW50cyBhbmQgbGluZSBzZWdtZW50cy4KCmBgYHtyfQpnZ3Bsb3QoYW15NzUsIGFlcyh4ID0gMTpucm93KGFteTc1KSwgeSA9IHByZXNzdXJlKSkgKyAKICBnZW9tX2xpbmUoYWVzKHNpemUgPSB3aW5kKSwgY29sb3IgPSAiZ3JheSIpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBzdGF0dXMsIHNpemUgPSB3aW5kKSkgCmBgYAoKLS0tCgojIyBFeGVyY2lzZQoKMSkgVXNlICJnZ3Bsb3QyIiBmdW5jdGlvbnMgdG8gbWFrZSBhIHNpbmdsZSBzY2F0dGVycGxvdCBvZiB3aW5kIGFuZCBwcmVzc3VyZSBmb3IgYWxsIHN0b3Jtcy4gVXNlIGNhdGVnb3J5IHRvIGFkZCBjb2xvciB0byB0aGUgZG90cy4KCmBgYHtyfQpnZ3Bsb3Qoc3Rvcm1zLCBhZXMoeCA9IHdpbmQsIHkgPSBwcmVzc3VyZSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjYXRlZ29yeSkpCmBgYAoKCjIpIFVzZSAiZ2dwbG90MiIgZnVuY3Rpb25zIHRvIG1ha2UgYSBzY2F0dGVycGxvdCBvZiB3aW5kIGFuZCBwcmVzc3VyZSBmb3IgYWxsIHN0b3JtcywgZmFjZXR0aW5nIGJ5IG1vbnRoLCBhbmQgdXNpbmcgY2F0ZWdvcnkgdG8gZGlmZmVyZW50aWF0ZSBieSBjb2xvci4KCmBgYHtyfQpnZ3Bsb3Qoc3Rvcm1zLCBhZXMoeCA9IHdpbmQsIHkgPSBwcmVzc3VyZSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjYXRlZ29yeSkpICsgCiAgZmFjZXRfd3JhcCh+IG1vbnRoKQpgYGAKCgozKSBVc2UgImdncGxvdDIiIGZ1bmN0aW9ucyB0byBtYWtlIGEgc2NhdHRlcnBsb3Qgb2Ygd2luZCBhbmQgcHJlc3N1cmUgZm9yIGFsbCBzdG9ybXMsIGJ1dCBub3cgY3JlYXRlIGZhY2V0cyBiYXNlZCBvbiBtb250aC4gRmVlbCBmcmVlIHRvIGFkZCBzb21lIGFtb3VudCBvZiBhbHBoYSB0cmFuc3BhcmVuY3kgdG8gdGhlIGNvbG9yIG9mIGRvdHMuCgpgYGB7cn0KZ2dwbG90KHN0b3JtcywgYWVzKHggPSB3aW5kLCB5ID0gcHJlc3N1cmUpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY2F0ZWdvcnkpLCBhbHBoYSA9IDAuMikgKyAKICBmYWNldF93cmFwKH4gbW9udGgpCmBgYAoKCjQpIENyZWF0ZSBib3hwbG90cyBvZiBwcmVzc3VyZSwgZm9yIHN0b3JtcyBpbiAxOTgwLiBZb3UgY2FuIGFsc28gdHJ5IGdyYXBoaW5nIHZpb2xpbnMgKGdlb21fdmlvbGluKCkpIGluc3RlYWQgb2YgYm94cGxvdHMgKGdlb21fYm94cGxvdCgpKS4KCmBgYHtyfQpzdG9ybXM4MCA8LSBmaWx0ZXIoc3Rvcm1zLCB5ZWFyID09IDE5ODApCgpnZ3Bsb3Qoc3Rvcm1zODAsIGFlcyh4ID0gbmFtZSwgeSA9IHByZXNzdXJlKSkgKyAKICBnZW9tX2JveHBsb3QoKQoKZ2dwbG90KHN0b3JtczgwLCBhZXMoeCA9IG5hbWUsIHkgPSBwcmVzc3VyZSkpICsgCiAgZ2VvbV92aW9saW4oKQpgYGAKCgo1KSBNYWtlIGEgc2NhdHRlcnBsb3Qgb2Ygd2luZCAoeC1heGlzKSBhbmQgdHNfZGlhbWV0ZXIgKHktYXhpcyksIGFuZCBhZGQgYSByZWdyZXNzaW9uIGxpbmXigJR2aWEgZ2VvbV9zbW9vdGgoKS4KCmBgYHtyfQpnZ3Bsb3Qoc3Rvcm1zLCBhZXMoeCA9IHdpbmQsIHkgPSB0c19kaWFtZXRlcikpICsgCiAgZ2VvbV9wb2ludChuYS5ybSA9IFRSVUUpICsgIyByZW1vdmUgbWlzc2luZyB2YWx1ZXMgZnJvbSB0aGUgZGF0YQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIG5hLnJtID0gVFJVRSkKYGBgCgoKVHJ5IGdlb21fc21vb3RoKCkgd2l0aCBtZXRob2QgPSBsbSB0byBmaXQgYSBsZWFzdCBzcXVhcmVzIHJlZ3Jlc3Npb24gbGluZS4KClRyeSBnZW9tX3Ntb290aCgpIHdpdGggbWV0aG9kID0gbG9lc3MgdG8gZml0IGEgbG9jYWwgcG9seW5vbWlhbCByZWdyZXNzaW9uLgoKYGBge3J9CmdncGxvdChzdG9ybXMsIGFlcyh4ID0gd2luZCwgeSA9IHRzX2RpYW1ldGVyKSkgKyAKICBnZW9tX3BvaW50KG5hLnJtID0gVFJVRSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBuYS5ybSA9IFRSVUUpCmBgYAoKCjYpIFJlcGVhdCB0aGUgcHJldmlvdXMgc2NhdHRlcnBsb3Qgb2Ygd2luZCAoeC1heGlzKSBhbmQgdHNfZGlhbWV0ZXIgKHktYXhpcyksIGJ1dCBub3cgdXNlIHN0YXR1cyB0byBjb2xvciBjb2RlIHRoZSBwb2ludHMsIGFuZCB1c2UgdGhlIGFscGhhIGFyZ3VtZW50IHRvIGFkZCBzb21lIHRyYW5zcGFyZW5jeSB0byB0aGUgZG90cy4KCmBgYHtyfQpnZ3Bsb3Qoc3Rvcm1zLCBhZXMoeCA9IHdpbmQsIHkgPSB0c19kaWFtZXRlcikpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBzdGF0dXMpLCBhbHBoYSA9IDAuNSwgbmEucm0gPSBUUlVFKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIG5hLnJtID0gVFJVRSkKYGBgCgoKNykgVGFrZSBhIGxvb2sgYXQgdGhlIGNoZWF0c2hlZXQgb2YgImdncGxvdDIiIGFuZCBtYWtlIGF0IGxlYXN0IDUgbW9yZSBkaWZmZXJlbnQgZ3JhcGhzIChlLmcuIG9mIG9uZSB2YXJpYWJsZSwgb2YgdHdvIHZhcmlhYmxlcywgb2YgdGhyZWUgdmFyaWFibGVzKS4KCmBgYHtyfQojIG9uZSB2YXJpYWJsZQpnZ3Bsb3Qoc3Rvcm1zKSArIGdlb21fcXEoYWVzKHNhbXBsZSA9IHByZXNzdXJlKSkKCmdncGxvdChzdG9ybXMpICsgZ2VvbV9iYXIoYWVzKHggPSBzdGF0dXMpKQoKIyB0d28gdmFyaWFibGVzCmdncGxvdChjb3VudChzdG9ybXNfeWVhcl9uYW1lKSwgYWVzKHggPSB5ZWFyLCB5ID0gbikpICsgZ2VvbV9saW5lKCkKCmdncGxvdChzdG9ybXMsIGFlcyh4ID0gd2luZCwgeSA9IHByZXNzdXJlKSkgKyBnZW9tX2RlbnNpdHkyZCgpCgojIHRocmVlIHZhcmlhYmxlcwpnZ3Bsb3Qoc3Rvcm1zLCBhZXMoeCA9IHdpbmQsIHkgPSBwcmVzc3VyZSkpICsgZ2VvbV90aWxlKGFlcyhmaWxsID0gc3RhdHVzKSkKYGBgCgo=